/*
 * CombatView.java
 *
 * @author Michael Hansen
 * @author Lukas Thuernagel
 * @author Soeren Warszus
 */

package risk.game;

import risk.dice.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 *
 * 
 */
public class CombatView extends JPanel {
    /**
     * Das zugehoerige Model
     */
    private CombatModel model = null;
    
    /**
     * Der dazugehoerige Controller
     */
    private CombatController controller = null;
    
    /**
     * FrontController, der auf Statusaenderungen reagieren soll
     */
    private FrontController frontController = null;

    /**
     * Button zum Ausloesen eines Wuerfelwurfs
     */
    private JButton buttonDice;
    
    /**
     * Anzeigebereich fuer die Verteidigerwuerfel
     */
    private JPanel panelDefender;
    
    /**
     * Anzeigebereich fuer die Angreiferwuerfel
     */
    private JPanel panelAttacker;
    
    /**
     * Anzeige des Angreiferlandes
     */
    private JLabel labelAttacker;
    
    /**
     * Anzeige des Verteidigerlandes
     */
    private JLabel labelDefender;

    /**
     * Benoetigte Views fuer die Anzeige der Angreifer- und Verteidigerwuerfel
     */
    private DiceView defender1;
    private DiceView defender2;
    private DiceView attacker1;
    private DiceView attacker2;
    private DiceView attacker3;
    
    /**
     * Auswahl der Anzahl der Wuerfel des Angreifers
     */
    JSlider armySize;
    
    /**
     * Erstellt eine neue Instanz von CombatView.
     *
     * @param model  Das dazugehoerige CombatModel.
     * @param fc     Instanz des FrontControllers.
     */
    public CombatView(CombatModel model, FrontController fc) {
        // Instanzvariable setzen
        this.model = model;
        this.frontController = fc;
        
        // eigene Instanz beim Model registrieren
        model.registerView(this, frontController); 
        
        // Internen Controller anlegen
        this.controller = new CombatController(model, this);
        
        // Darstellung initialisieren
        initializeView();
    }
    
    /**
     * Die Methode aktualisiert die Darstellung von Angreifer- und
     * Verteidigerland.
     * Hierbei werden die Namen der Laender neu eingetragen, die jeweiligen 
     * Wuerfel und die Angreifertruppenzahlen neu gesetzt.
     */
    public void updateCombatant() {
        this.resetDice();
        
        // Angreifer und Verteidigerland
        this.labelAttacker.setText(this.model.getAttacker().getName());
        this.labelDefender.setText(this.model.getDefender().getName());
        
        // Gleich mal die Verteidigerwuerfel anzeigen
        this.updateDefenderDice(this.model.getDefender().getArmySize());
        this.updateAttackerDice(this.model.getArmySize());
        this.updateArmySize();
  
        // button zum wuerfeln aktivieren
        this.buttonDice.setEnabled(true);
    }
    
    /**
     * Aktualisiert die Anzeige der Angreiferwuerfel.
     * Hierbei handelt es sich nur um das Anzeigen der Anzahl der Wuerfel. Das
     * Visualisieren eines Wuerfelwurfes uebernimmt der DiceView selbst.
     */
    public void updateAttackerDice(int newValue) {
        switch (newValue) {
            case 1:
                this.attacker1.setVisible(true);
                this.attacker2.setVisible(false);
                this.attacker3.setVisible(false);
                break;
            case 2:
                this.attacker1.setVisible(true);
                this.attacker2.setVisible(true);
                this.attacker3.setVisible(false);
                break;
            case 3:
                this.attacker1.setVisible(true);
                this.attacker2.setVisible(true);
                this.attacker3.setVisible(true);
                break;
        } 
    }
    
    /**
     * Aktualisiert die Anzeige der Verteidigerwuerfel.
     * Hierbei handelt es sich nur um das Anzeigen der Anzahl der Wuerfel. Das
     * Visualisieren eines Wuerfelwurfes uebernimmt der DiceView selbst.
     */
    public void updateDefenderDice(int newValue) {
       if (newValue >= 2){
            // 2 verteidigende Wuerfel
            this.defender1.setVisible(true);
            this.defender2.setVisible(true);
        } else {
            // 1 verteidigender Wuerfel
            this.defender1.setVisible(true);
            this.defender2.setVisible(false);
        }
    }
    
    /**
     * Aktualisieren des JSliders zur Auswahl der Angreifertruppen. 
     * Dieser muss je nach Vorhandensein von Angreifertruppen entsprechend im
     * Maximum und ausgewaehltem Wert angepasst werden.
     */
    public void updateArmySize() {
        this.armySize.setMaximum(this.model.getArmySize());
        this.armySize.setValue(this.model.getArmySize());
        this.armySize.setEnabled(true);
    }
    
    /**
     * Gibt den momentan vom JSlider selektierten Wert zurueck.
     */
    public int getArmySize() {
        return this.armySize.getValue();
    }
    
    
    /**
     * Setzt den View wieder in die Ausgangsdarstellung zurueck.
     */
    public void reset() {
        // Angreifer- und Verteidigerland
        this.labelAttacker.setText("");
        this.labelDefender.setText("");

        this.attacker1.setVisible(false);
        this.attacker2.setVisible(false);
        this.attacker3.setVisible(false);
        
        this.defender1.setVisible(false);
        this.defender2.setVisible(false);

        this.buttonDice.setEnabled(false);
        this.armySize.setEnabled(false);
        
        this.resetDice();
    }
    
    /**
     * Setzt saemtliche Wuerfel wieder in den Ausgangszustand zurueck.
     */
    private void resetDice() {
        this.defender1.reset();
        this.defender2.reset();
        this.attacker1.reset();
        this.attacker2.reset();
        this.attacker3.reset();
    }
    
    /**
     * Deaktiviert den Button zum Wuerfeln. 
     * In einigen Situationen darf der Benutzer nicht weiter wuerfeln, z.B. wenn
     * das Angreiferland nur noch eine Armee im eigenen Land hat.
     */
    public void disableDicing() {
        this.buttonDice.setEnabled(false);
    }
    
    /**    
     * Die Methode initialisiert den View mit den Standardwerten vor einem 
     * Kampf.
     */
    private void initializeView() {    
        // Layout-Manager definieren
        GridBagLayout gbl      = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();
        int columnWidths[] = {100, 200, 100, 200, 150};
        int rowHeights[]   = {20, 120, 20, 20};
        
        gbl.columnWidths = columnWidths;
        gbl.rowHeights   = rowHeights;
        this.setLayout(gbl);
        
        // Anzeige des Labels "Angreifer"
        gbc.gridx = 0;
	gbc.gridy = 0;
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;
        JLabel labelAttacker = new JLabel("Angreifer:");
        gbl.setConstraints(labelAttacker, gbc);
        this.add(labelAttacker);
        
        
        // Anzeige des angreifenden Landes
        gbc.gridx = 1;
	gbc.gridy = 0;
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;
        this.labelAttacker = new JLabel("");
        gbl.setConstraints(this.labelAttacker, gbc);
        this.add(this.labelAttacker);


        // Anzeige des Labels "Verteidiger"
        gbc.gridx = 2;
	gbc.gridy = 0;
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;
        JLabel labelDefender = new JLabel("Verteidiger:");
        gbl.setConstraints(labelDefender, gbc);
        this.add(labelDefender);

        
        // Anzeige des verteidigenden Landes
        gbc.gridx = 3;
	gbc.gridy = 0;
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;
        this.labelDefender = new JLabel("");
        gbl.setConstraints(this.labelDefender, gbc);
        this.add(this.labelDefender);
        

        // Anzeige der Wuerfel fuer den Angreifer
        gbc.gridx = 1;
	gbc.gridy = 1;
        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
        GridLayout gl = new GridLayout(0, 1);
        gl.setVgap(2);
        this.panelAttacker = new JPanel();
        this.panelAttacker.setLayout(gl);
        
        this.attacker1 = new DiceView(model.getAttackerDiceModel()); 
        this.attacker1.setVisible(false);
        this.panelAttacker.add(attacker1);  
        this.attacker2 = new DiceView(model.getAttackerDiceModel());
        this.attacker2.setVisible(false);
        this.panelAttacker.add(attacker2);
        this.attacker3 = new DiceView(model.getAttackerDiceModel());
        this.attacker3.setVisible(false);
        this.panelAttacker.add(attacker3);

        gbl.setConstraints(this.panelAttacker, gbc);
        this.add(this.panelAttacker);
        
        
        // Anzeige der Wuerfel fuer den Verteidiger
        gbc.gridx = 3;
	gbc.gridy = 1;
        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
        this.panelDefender = new JPanel();
        this.panelDefender.setLayout(gl);
        
        this.defender1 = new DiceView(model.getDefenderDiceModel());
        this.defender1.setVisible(false);
        this.panelDefender.add(this.defender1);
        this.defender2 = new DiceView(model.getDefenderDiceModel());
        this.defender2.setVisible(false);
        this.panelDefender.add(this.defender2);
        
        gbl.setConstraints(this.panelDefender, gbc);
        this.add(this.panelDefender);
        
        
        // Laben fuer die Truppenanzahl
        gbc.gridx = 0;
	gbc.gridy = 2;
        gbc.gridwidth = 2;
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;
        JLabel labelArmySize = new JLabel("Angreifende Wuerfel:");
        gbl.setConstraints(labelArmySize, gbc);
        this.add(labelArmySize);
        
        
        // Anzeige von ToggleButton zur Auswahl der Truppenanzahl
        gbc.gridx = 0;
	gbc.gridy = 3;
        gbc.gridwidth = 2;
        gbc.anchor = GridBagConstraints.WEST;
        this.armySize = new JSlider(JSlider.HORIZONTAL, 1, 3, 3);
        this.armySize.addChangeListener(this.controller);
        
        this.armySize.setMajorTickSpacing(1);
        this.armySize.setMinorTickSpacing(1);
        this.armySize.setPaintTicks(true);
        this.armySize.setPaintLabels(true);
        this.armySize.setEnabled(false);
        gbl.setConstraints(armySize, gbc);
        this.add(armySize);
  
        
        // Anzeige fuer den Abbruch eines Angriffs
        gbc.gridx = 2;
	gbc.gridy = 3;
        gbc.gridwidth = 2;
        gbc.anchor = GridBagConstraints.EAST;
        this.buttonDice = new JButton("wuerfeln");
        this.buttonDice.setEnabled(false);
        this.buttonDice.addActionListener(this.controller);
        
        buttonDice.setActionCommand("dice");
        gbl.setConstraints(buttonDice, gbc);
        this.add(buttonDice);
 
        // Anzeige des Buttons zum Beenden der Kampfphase
        gbc.gridx = 4;
	gbc.gridy = 3;
        gbc.anchor = GridBagConstraints.CENTER;
        JButton buttonFinish = new JButton("Spielzug beenden");
        buttonFinish.addActionListener(this.frontController);
        buttonFinish.setActionCommand("finishCombatState");
        gbl.setConstraints(buttonFinish, gbc);
        this.add(buttonFinish);
        
        this.setVisible(true);
    }
}
